﻿using Dyao.Book.Application.Abstractions;
using Dyao.Book.Contract;

namespace Dyao.Book.Application
{
    public class TaskCenterRequestParamsSerializerService : BaseApplication, ITaskCenterRequestParamsSerializer, ITaskCenterRequestParamsSerializerSetter
    {
        private Func<int, Task<string>> _paramsLoader;

        /// <summary>
        /// 序列化
        /// </summary>
        /// <param name="actionKey"></param>
        /// <param name="catetory"></param>
        /// <param name="requestParams"></param>
        /// <param name="cancellationToken"></param>
        /// <returns></returns>
        public Task<string> SerializeAsync(string actionKey, TaskCenterCategoryEnum catetory, object requestParams, CancellationToken cancellationToken = default)
        {
            string result = requestParams is ITaskCenterParameters p ? p.ToString() : DefaultJsonSerialize(requestParams);

            return Task.FromResult(result);
        }

        /// <summary>
        /// 反序列化
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="taskId"></param>
        /// <param name="actionKey"></param>
        /// <param name="catetory"></param>
        /// <param name="cancellationToken"></param>
        /// <returns></returns>
        public async Task<T> DeserializeAsync<T>(int taskId, string actionKey, TaskCenterCategoryEnum catetory, CancellationToken cancellationToken = default)
        {

            if (taskId == 0)
            {
                throw new ArgumentException("记录id不能为0", nameof(taskId));
            }

            var loader = _paramsLoader == null ? GetRequestParamsAsync : _paramsLoader;

            var str = await loader(taskId);


            object result = default(T);

            var type = typeof(T);
            if ((type.IsInterface && typeof(ITaskCenterParameters).IsAssignableFrom(type))
                || (typeof(DefaultTaskCenterParameters).IsAssignableFrom(type)))
            {
                var handledStr = str;

                Func<IDictionary<string, object>> dictFactory = () => JsonSerializer.Deserialize<Dictionary<string, object>>(handledStr);

                if (type.IsGenericType &&
                    (type.GetGenericTypeDefinition() == typeof(ITaskCenterParameters<>)
                    || type.GetGenericTypeDefinition() == typeof(DefaultTaskCenterParameters<>)))
                {
                    var underlyType = type.GetGenericArguments()[0];
                    result = DefaultTaskCenterParameters.Create(underlyType, handledStr, null, null, dictFactory, DefaultJsonDeserialize);
                }
                else
                {
                    result = new DefaultTaskCenterParameters(handledStr, dictFactory, DefaultJsonDeserialize);
                }
            }
            else
            {
                result = DefaultJsonDeserialize(type, str);
            }

            return (T)result;
        }

        public string DefaultJsonSerialize(object requestParams)
        {
            string result = null;
            if (requestParams != null)
            {
                if (IsPrimitive(requestParams))
                {
                    result = requestParams.ToString();
                }
                else
                {
                    result = JsonSerializer.Serialize(requestParams);
                }
            }

            return result;
        }

        public virtual object DefaultJsonDeserialize(Type type, object str)
        {
            if (type == typeof(string)) return str;

            return JsonSerializer.Deserialize(type, str?.ToString());
        }


        public void SetParametersStringLoader(Func<int, Task<string>> paramsLoader)
        {
            this._paramsLoader = paramsLoader;
        }

        private bool IsPrimitive(object obj)
        {
            var t = obj.GetType();
            return (t == typeof(string) || t.IsPrimitive);
        }

        private async Task<string> GetRequestParamsAsync(int id)
        {
            return await Task.FromResult<string>("");
        }
    }
}
